package org.xmap.ui.base;

import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;

import org.xmap.ui.Theme;
import org.xmap.ui.UIUtil;
import org.xmap.ui.View;

/**
 * <p>窗口基类，所有的界面对象都派生于该类，每一个界面对象都是一个窗口。</p>
 * @author Zealot
 * @version 1.0
 */
public abstract class Window {

    /**
     * 定义左上角对齐的对齐方式。
     */
    public static final int ORIENT_LEFT_UP = 0;
    /**
     * 定义左下角对齐的对齐方式。
     */
    public static final int ORIENT_LEFT_DOWN = 1;
    /**
     * 定义右上角对齐的对齐方式。
     */
    public static final int ORIENT_RIGHT_UP = 2;
    /**
     * 定义右下角对齐的对齐方式。
     */
    public static final int ORIENT_RIGHT_DOWN = 3;
    /**
     * 定义拉伸的绘制背景方式。
     */
    public static final int IMAGE_STRETCH = 0; // 拉伸
    /**
     * 定义平铺的绘制背景方式。
     */
    public static final int IMAGE_TILE = 1; // 平铺
    /**
     * 定义居中的绘制背景方式。
     */
    public static final int IMAGE_CENTER = 2; // 居中
    /**
     * 定义显示方式为左对齐。
     */
    public static final int ALIGN_LEFT = 0;
    /**
     * 定义显示方式为居中对齐。
     */
    public static final int ALIGN_CENTER = 1;
    /**
     * 定义显示方式为右对齐。
     */
    public static final int ALIGN_RIGHT = 2;
    /**
     * 定义水平方向的拉伸方式。
     */
    public static final int SCRETCH_ROW = 0x00000001;
    /**
     * 定义垂直方向的拉伸方式。
     */
    public static final int SCRETCH_COLUMN = 0x00000002;
    /**
     * 定义滚动条的宽度。
     */
    public static final int STROLL_WIDTH = 5;

    // Window拥有
    public static final int STATE_ENABLE = 0x00000001; // 是否可用，如果可用，则处理按键和触笔等事件；如果不可用，则不处理。
    public static final int STATE_ENABLE_BACKUP = 0x00000002; // 是否可用的备份。
    public static final int STATE_SHOW = 0x00000004; // 在屏幕上是否可见。
    public static final int STATE_CAN_FOCUS = 0x00000008; // 是否可以接受焦点。
    public static final int STATE_FOCUS = 0x00000010; // 当前是否处于焦点。
    public static final int STATE_SET_CLIP_BEFORE_DRAW = 0x00000020; // 绘制之前是否需要裁剪。
    public static final int STATE_POINTER_SELECTED = 0x00000040; // 是否已经接受过触笔事件。
    public static final int STATE_BACKGROUND_IMAGE_STRETCH = 0x00000080; // 是否拉伸。
    public static final int STATE_BACKGROUND_IMAGE_CENTER = 0x00000100; // 居中或平铺，只有不拉伸，该参数才有效。
    public static final int STATE_SHOW_RECT = 0x00000200; // 是否显示边框。

    public static final int STATE_BACKGROUND_TRANSPARENT = 0x00000400; // 是否背景透明。
    public static final int STATE_TEXT_ALIGN_CENTER = 0x00000800; // 是否文字居中。
    public static final int STATE_TEXT_ALIGN_LEFT = 0x00001000; // 是否文字左对齐，只有文字不居中才有效。

    public static final int STATE_MENUBAR_ENABLE_LEFT_MENU = 0x00002000; // 是否启用左侧菜单

    /**
     * 当前窗口区域。
     */
    protected final Rect rect;
    /**
     * 当前窗口的状态。
     */
    protected int state;
    /**
     * 拥有当前窗口的视图。
     */
    protected View owner;
    /**
     * 当前窗口的背景颜色。
     */
    protected int bgColor;
    /**
     * 当前窗口的原始背景图像。
     */
    protected Image bgImage;
    /**
     * 触笔按下的纵坐标。
     */
    protected int pointerPressedY;

    /**
     * 通过指定区域来构造窗口。
     * @param r Rect 区域。
     */
    public Window(Rect r) {
        this(r.leftUp.x, r.leftUp.y, r.width, r.height, Window.ORIENT_LEFT_UP);
    }

    /**
     * 通过指定坐标、宽高来构造窗口。
     * @param leftUpX int 左上角的横坐标。
     * @param leftUpY int 左上角的纵坐标。
     * @param width int 窗口宽度。
     * @param height int 窗口高度。
     */
    public Window(int leftUpX, int leftUpY, int width, int height) {
        this(leftUpX, leftUpY, width, height, Window.ORIENT_LEFT_UP);
    }

    /**
     * 通过指定坐标的锚点、宽高来构造窗口。
     * @param x int 锚点横坐标。
     * @param y int 锚点纵坐标。
     * @param width int 窗口宽度。
     * @param height int 窗口高度。
     * @param orient int 锚点类型，可以是左上、左下、右上、右下四种。
     */
    public Window(int x, int y, int width, int height, int orient) {
        int realLeftUpX = 0;
        int realLeftUpY = 0;
        switch (orient) {
        case ORIENT_LEFT_UP:
            realLeftUpX = x;
            realLeftUpY = y;
            break;
        case ORIENT_LEFT_DOWN:
            realLeftUpX = x;
            realLeftUpY = y - height;
            break;
        case ORIENT_RIGHT_UP:
            realLeftUpX = x - width;
            realLeftUpY = y;
            break;
        case ORIENT_RIGHT_DOWN:
            realLeftUpX = x - width;
            realLeftUpY = y - height;
            break;
        }
        this.rect = new Rect(realLeftUpX, realLeftUpY, width, height);
        this.state = 0;
        this.setEnable(true);
        this.setShow(true);
        this.setCanFocus(false);
        this.setFocus(false);
        this.setSetClipBeforeDraw(false);
        this.setPointerSelected(false);
        this.setBackgroundImageStretch(false);
        this.setBackgroundImageCenter(true);
        this.setShowRect(false);
        this.owner = null;
        this.bgColor = Theme.instance.viewBackgroundColor;
        this.bgImage = null;
        this.pointerPressedY = 0;
    }

    /**
     * 重新设置窗口的区域。
     * @param leftUpX int 窗口左上角坐标。
     * @param leftUpY int 窗口右上角坐标。
     * @param width int 窗口宽度。
     * @param height int 窗口高度。
     */
    public void setRect(int leftUpX, int leftUpY, int width, int height) {
        this.rect.setRect(leftUpX, leftUpY, width, height);
        this.processBgImage();
    }

    /**
     * 获得窗口的区域。
     * @return Rect 窗口区域。
     */
    public final Rect getRect() {
        return this.rect;
    }

    /**
     * 设置窗口是否可用。
     * @param enable boolean 是否可用。
     */
    public final void setEnable(boolean enable) {
        if (enable) {
            this.state |= Window.STATE_ENABLE;
        } else {
            this.state &= ~Window.STATE_ENABLE;
        }
    }

    /**
     * 获得当前窗口是否可用。
     * @return boolean 是否可用。
     */
    public final boolean getEnable() {
        return (this.state & Window.STATE_ENABLE) != 0;
    }

    /**
     * 设置窗口是否可用。
     */
    public final void setEnablebackup() {
        if (this.getEnable()) {
            this.state |= Window.STATE_ENABLE_BACKUP;
        } else {
            this.state &= ~Window.STATE_ENABLE_BACKUP;
        }
    }

    /**
     * 获得当前窗口上一次的是否可用结果。
     * @return boolean 是否可用。
     */
    public final boolean getEnableBackup() {
        return (this.state & Window.STATE_ENABLE_BACKUP) != 0;
    }

    /**
     * 设置窗口是否可见。
     * @param show boolean 是否可见。
     */
    public final void setShow(boolean show) {
        if (show) {
            this.state |= Window.STATE_SHOW;
        } else {
            this.state &= ~Window.STATE_SHOW;
        }
    }

    /**
     * 获得当前窗口是否可见。
     * @return boolean 是否可见。
     */
    public final boolean getShow() {
        return (this.state & Window.STATE_SHOW) != 0;
    }

    /**
     * 设置当前窗口是否可以聚焦。
     * @param canFocus boolean 是否可以聚焦。
     */
    public final void setCanFocus(boolean canFocus) {
        if (canFocus) {
            this.state |= Window.STATE_CAN_FOCUS;
        } else {
            this.state &= ~Window.STATE_CAN_FOCUS;
        }
    }

    /**
     * 获得当前窗口是否可以聚焦。
     * @return boolean 是否可以聚焦。
     */
    public final boolean getCanFocus() {
        return (this.state & Window.STATE_CAN_FOCUS) != 0;
    }

    /**
     * 设置当前窗口是否聚焦，该方法没有设置成final，是因为扩展类需要扩展这个函数来实现更多的功能。
     * @param focus boolean 是否聚焦。
     * @return boolean 是否设置成功。
     */
    public boolean setFocus(boolean focus) {
        if (this.getCanFocus()) {
            if (focus) {
                this.state |= Window.STATE_FOCUS;
            } else {
                this.state &= ~Window.STATE_FOCUS;
            }
            return true;
        }
        return false;
    }

    /**
     * 返回当前窗口是否聚焦。
     * @return boolean 是否聚焦。
     */
    public final boolean getFocus() {
        return (this.state & Window.STATE_FOCUS) != 0;
    }

    /**
     * 指定绘制之前是否设置裁剪。
     * @param setClipBeforeDraw boolean 绘制之前是否设置裁剪。
     */
    public final void setSetClipBeforeDraw(boolean setClipBeforeDraw) {
        if (setClipBeforeDraw) {
            this.state |= Window.STATE_SET_CLIP_BEFORE_DRAW;
        } else {
            this.state &= ~Window.STATE_SET_CLIP_BEFORE_DRAW;
        }
    }

    /**
     * 获得绘制之前是否设置裁剪。
     * @return boolean 绘制之前是否设置裁剪。
     */
    public final boolean getSetClipBeforeDraw() {
        return (this.state & Window.STATE_SET_CLIP_BEFORE_DRAW) != 0;
    }

    public void setPointerSelected(boolean pointerSelected) {
        if (pointerSelected) {
            this.state |= Window.STATE_POINTER_SELECTED;
        } else {
            this.state &= ~Window.STATE_POINTER_SELECTED;
        }
    }

    public final boolean getPointerSelected() {
        return (this.state & Window.STATE_POINTER_SELECTED) != 0;
    }

    /**
     * 设置背景图像是否拉伸。
     * @param stretch boolean 是否拉伸。
     */
    public void setBackgroundImageStretch(boolean stretch) {
        if (stretch) {
            this.state |= Window.STATE_BACKGROUND_IMAGE_STRETCH;
            this.processBgImage();
        } else {
            this.state &= ~Window.STATE_BACKGROUND_IMAGE_STRETCH;
        }
    }

    /**
     * 获得背景图像是否拉伸。
     * @return boolean 是否拉伸。
     */
    public boolean getBackgroundImageStretch() {
        return (this.state & Window.STATE_BACKGROUND_IMAGE_STRETCH) != 0;
    }

    /**
     * 设置背景图像是居中还是平铺，true为居中，false为平铺。
     * @param center boolean 居中或者平铺。
     */
    public void setBackgroundImageCenter(boolean center) {
        if (center) {
            this.state |= Window.STATE_BACKGROUND_IMAGE_CENTER;
        } else {
            this.state &= ~Window.STATE_BACKGROUND_IMAGE_CENTER;
        }
    }

    /**
     * 获得背景图像是居中还是平铺。
     * @return boolean 居中或者平铺。
     */
    public boolean getBackgroundImageCenter() {
        return (this.state & Window.STATE_BACKGROUND_IMAGE_CENTER) != 0;
    }

    /**
     * 设置是否显示边框。
     * @param showRect boolean 是否显示边框。
     */
    public void setShowRect(boolean showRect) {
        if (showRect) {
            this.state |= Window.STATE_SHOW_RECT;
        } else {
            this.state &= ~Window.STATE_SHOW_RECT;
        }
    }

    /**
     * 获得是否显示边框。
     * @return boolean 是否显示边框。
     */
    public boolean getShowRect() {
        return (this.state & Window.STATE_SHOW_RECT) != 0;
    }

    /**
     * 设置窗口的拥有者。
     * @param owner View 拥有该窗口的View。
     */
    public final void setOwner(View owner) {
        this.owner = owner;
    }

    /**
     * 获得当前窗口的拥有者。
     * @return View 拥有该窗口的View。
     */
    public final View getOwner() {
        return this.owner;
    }

    /**
     * 指定当前窗口的背景颜色。
     * @param color int 背景颜色。
     */
    public final void setBgColor(int color) {
        this.bgColor = color;
    }

    /**
     * 获得当前窗口的背景颜色。
     * @return int 背景颜色。
     */
    public final int getBgColor() {
        return this.bgColor;
    }

    /**
     * 设置当前窗口的背景图像。
     * @param image Image 背景图像。
     */
    public final void setBgImage(Image image) {
        this.bgImage = image;
        this.processBgImage();
    }

    /**
     * 获得当前窗口的背景图像。
     * @return Image 当前窗口的背景图像。
     */
    public final Image getBgImage() {
        return this.bgImage;
    }

    /**
     * 留给派生类使用的绘制函数，派生类重写这个函数来实现绘制。
     * @param g Graphics 图形句柄。
     */
    public void draw(Graphics g) {
    }

    /**
     * 按键事件处理函数，默认所有的按键事件都被处理。
     * @param flag boolean 是按下还是抬起。
     * @param keyCode int 按键代码。
     * @param gameAction int 动作代码。
     * @return boolean 是否处理该事件。
     */
    public boolean keyEvent(boolean flag, int keyCode, int gameAction) {
        // todo 需要改成false
        return true;
    }

    /**
     * 触笔事件处理函数，默认所有的触笔事件都被处理。
     * @param ev Event 触笔事件。
     * @return boolean 是否处理该事件。
     */
    public boolean pointerEvent(Event ev) {
        // todo 需要改成false
        return true;
    }

    /**
     * 通知该窗口，屏幕的宽度和高度已经改变，是屏幕的宽度和高度，而不是窗口的宽度和高度，该函数用于窗口根据屏幕大小修改自己的大小。
     * @param width int 新的屏幕宽度。
     * @param height int 新的屏幕高度。
     */
    public void sizeChanged(int width, int height) {
    }

    /**
     * 时间触发函数，当窗口需要自己的逻辑的时候，通过重写该函数来实现。
     */
    public void update() {
    }

    /**
     * 根据当前的绘制方式来计算背景图片。
     */
    protected void processBgImage() {
        if (this.getBackgroundImageStretch()) {
            if (this.bgImage != null) {
                int width = this.getRect().width;
                int height = this.getRect().height;
                if (width > 0 && height > 0 && (this.bgImage.getWidth() != width || this.bgImage.getHeight() != height)) {
                    Image image = UIUtil.fastScale(this.bgImage, this.getRect().width, this.getRect().height);
                    this.bgImage = image;
                }
            }
        }
    }
}
